from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
import time
import re
import threading
import logging
import os
from selenium.common.exceptions import TimeoutException, NoSuchElementException, ElementClickInterceptedException, StaleElementReferenceException

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger('tracking')  # 使用tracking logger

# 创建debug目录的路径
DEBUG_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'debug')
# 确保debug目录存在
os.makedirs(DEBUG_DIR, exist_ok=True)

def _save_debug_info(driver, prefix):
    """保存调试信息到debug目录"""
    try:
        timestamp = int(time.time())
        # 保存截图
        screenshot_path = os.path.join(DEBUG_DIR, f"{prefix}_screenshot_{timestamp}.png")
        driver.save_screenshot(screenshot_path)
        logger.info(f"错误截图已保存: {screenshot_path}")
        
        # 保存页面源码
        source_path = os.path.join(DEBUG_DIR, f"{prefix}_page_source_{timestamp}.html")
        with open(source_path, "w", encoding="utf-8") as f:
            f.write(driver.page_source)
        logger.info(f"页面源代码已保存: {source_path}")
        
        # 打印当前页面的所有元素
        elements = driver.find_elements(By.XPATH, "//*")
        logger.info(f"当前页面元素数量: {len(elements)}")
        for element in elements[:10]:  # 只打印前10个元素
            try:
                logger.info(f"元素: {element.tag_name}, 文本: {element.text}, 类名: {element.get_attribute('class')}")
            except:
                pass
    except Exception as e:
        logger.error(f"保存调试信息失败: {str(e)}")

class SharedWebDriver:
    _instance = None
    _lock = threading.Lock()
    
    def __new__(cls, username=None, password=None):
        with cls._lock:
            if cls._instance is None:
                cls._instance = super(SharedWebDriver, cls).__new__(cls)
                cls._instance.driver = None
                cls._instance.username = username
                cls._instance.password = password
                cls._instance.initialized = False
            return cls._instance
    
    def __init__(self, username=None, password=None):
        if not self.initialized and username and password:
            self.username = username
            self.password = password
            self.initialized = True
    
    def initialize(self):
        """初始化WebDriver并登录"""
        if self.driver is None:
            try:
                logger.info("初始化ChromeDriver")
                chrome_options = Options()
                # 添加无头模式
                chrome_options.add_argument('--headless=new')
                chrome_options.add_argument('--disable-gpu')
                chrome_options.add_argument('--no-sandbox')
                chrome_options.add_argument('--disable-dev-shm-usage')
                chrome_options.add_argument('--disable-software-rasterizer')
                chrome_options.add_argument('--disable-extensions')
                chrome_options.add_argument('--disable-notifications')
                chrome_options.add_argument('--disable-popup-blocking')
                chrome_options.add_argument('--disable-infobars')
                chrome_options.add_argument('--disable-web-security')
                chrome_options.add_argument('--disable-features=IsolateOrigins,site-per-process')
                chrome_options.add_argument('--disable-site-isolation-trials')
                chrome_options.add_argument('--disable-extensions')
                chrome_options.add_argument('--disable-infobars')
                chrome_options.add_argument('--disable-notifications')
                chrome_options.add_argument('--disable-popup-blocking')
                chrome_options.add_argument('--disable-web-security')
                chrome_options.add_argument('--ignore-certificate-errors')
                chrome_options.add_argument('--window-size=1920,1080')
                chrome_options.add_argument('--start-maximized')
                chrome_options.add_argument('--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36')
                
                # 设置页面加载策略
                chrome_options.page_load_strategy = 'eager'
                
                # 使用webdriver_manager自动管理驱动
                service = Service(ChromeDriverManager().install())
                self.driver = webdriver.Chrome(service=service, options=chrome_options)
                
                # 设置超时时间
                self.driver.set_page_load_timeout(30)
                self.driver.set_script_timeout(30)
                self.driver.implicitly_wait(5)  # 减少隐式等待时间
                
                # 使用CDP设置用户代理
                self.driver.execute_cdp_cmd('Network.setUserAgentOverride', {
                    "userAgent": 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
                })
                
                logger.info("ChromeDriver 初始化成功")
                
                # 登录并导航
                self._login_and_navigate()
                
            except Exception as e:
                logger.error(f"初始化WebDriver失败: {str(e)}")
                if self.driver:
                    _save_debug_info(self.driver, "init_error")
                    self.driver.quit()
                self.driver = None
                raise
    
    def _login_and_navigate(self):
        """登录并导航到订单追踪页面"""
        try:
            logger.info("开始登录流程")
            self.driver.get('https://sso.fs.com/login?redirect_url=https://airplan.fs.com/YX_0evWtMz4373v/index.php')
            
            # 等待用户名输入框出现并输入
            username_input = WebDriverWait(self.driver, 10).until(
                EC.presence_of_element_located((By.ID, "username"))
            )
            username_input.clear()
            username_input.send_keys(self.username)
            
            # 等待密码输入框出现并输入
            password_input = WebDriverWait(self.driver, 10).until(
                EC.presence_of_element_located((By.ID, "password"))
            )
            password_input.clear()
            password_input.send_keys(self.password)
            
            # 点击登录按钮
            login_button = WebDriverWait(self.driver, 10).until(
                EC.element_to_be_clickable((By.CSS_SELECTOR, "button.fs-btn-primary"))
            )
            login_button.click()
            
            # 等待页面加载完成
            WebDriverWait(self.driver, 10).until(
                lambda d: d.execute_script('return document.readyState') == 'complete'
            )
            
            # 等待并点击"销售订单"菜单
            sales_menu = WebDriverWait(self.driver, 10).until(
                EC.element_to_be_clickable((By.ID, "p_menu_62"))
            )
            self.driver.execute_script("arguments[0].click();", sales_menu)
            
            # 等待菜单展开
            time.sleep(2)
            
            # 等待并点击"海外订单流程跟踪"链接
            tracking_link = WebDriverWait(self.driver, 10).until(
                EC.element_to_be_clickable((By.XPATH, "//a[@href='https://airplan.fs.com/YX_0evWtMz4373v/products_instock_shipping_sales_seattle.php']"))
            )
            self.driver.execute_script("arguments[0].click();", tracking_link)
            
            # 等待新页面加载
            WebDriverWait(self.driver, 10).until(
                lambda d: d.execute_script('return document.readyState') == 'complete'
            )
            
            logger.info("登录和导航流程完成")
            
        except Exception as e:
            logger.error(f"登录和导航过程中出错: {str(e)}")
            if self.driver:
                _save_debug_info(self.driver, "login_error")
                self.driver.quit()
            self.driver = None
            raise
    
    def search_order(self, order_no, max_retries=3):
        """搜索单个订单并获取物流信息"""
        if not self.driver:
            self.initialize()
            
        for retry in range(max_retries):
            try:
                logger.info(f"开始搜索订单: {order_no} (尝试 {retry+1}/{max_retries})")
                
                # 等待搜索框出现并输入订单号
                search_input = WebDriverWait(self.driver, 5).until(
                    EC.presence_of_element_located((By.CSS_SELECTOR, "input[name='search']"))
                )
                search_input.clear()
                search_input.send_keys(order_no)
                logger.info(f"已输入订单号: {order_no}")
                
                # 点击搜索按钮
                search_button = WebDriverWait(self.driver, 5).until(
                    EC.element_to_be_clickable((By.CSS_SELECTOR, "button.button01.btn-info"))
                )
                search_button.click()
                logger.info("已点击搜索按钮")
                
                # 等待搜索结果加载
                time.sleep(1)
                
                # 查找包含物流信息的a标签
                tracking_links = self.driver.find_elements(By.XPATH, "//a[contains(@onclick, 'Sagawa Express') or contains(@onclick, 'Yamato Transport')]")
                
                if tracking_links:
                    logger.info(f"找到 {len(tracking_links)} 个物流链接")
                    for link in tracking_links:
                        onclick = link.get_attribute('onclick')
                        if onclick:
                            # 提取onclick中的参数
                            match = re.search(r"get_tracking_info\('([^']+)','([^']+)'", onclick)
                            if match:
                                shipping_method = match.group(1)
                                tracking_number = match.group(2)
                                logger.info(f"成功获取物流信息 - 方式: {shipping_method}, 单号: {tracking_number}")
                                return [shipping_method, tracking_number]
                
                logger.warning(f"未找到订单 {order_no} 的物流信息")
                return None
                
            except (StaleElementReferenceException, TimeoutException) as e:
                logger.warning(f"查询订单 {order_no} 时出错 (尝试 {retry+1}/{max_retries}): {str(e)}")
                if retry < max_retries - 1:
                    # 如果出错，保存调试信息并尝试重新初始化WebDriver
                    if self.driver:
                        _save_debug_info(self.driver, f"search_error_{order_no}")
                        self.driver.quit()
                    self.driver = None
                    self.initialize()
                    time.sleep(2)  # 等待页面加载
                else:
                    logger.error(f"查询订单 {order_no} 失败，已达到最大重试次数")
                    if self.driver:
                        _save_debug_info(self.driver, f"search_error_final_{order_no}")
                    return None
            except Exception as e:
                logger.error(f"查询订单 {order_no} 时出错: {str(e)}")
                if self.driver:
                    _save_debug_info(self.driver, f"search_error_unexpected_{order_no}")
                return None
    
    def quit(self):
        """关闭WebDriver"""
        if self.driver:
            self.driver.quit()
            self.driver = None
            self.initialized = False

def get_shipping_info_batch(order_numbers, username, password):
    """批量处理多个订单，使用串行处理方式"""
    results = {}
    shared_driver = SharedWebDriver(username, password)
    
    try:
        # 初始化WebDriver
        shared_driver.initialize()
        
        # 串行处理订单
        for order_no in order_numbers:
            try:
                result = shared_driver.search_order(order_no)
                results[order_no] = result
                logger.info(f"已处理订单: {order_no}")
                time.sleep(1)  # 添加短暂延迟，避免请求过于频繁
            except Exception as e:
                logger.error(f"处理订单 {order_no} 时出错: {str(e)}")
                results[order_no] = None
    finally:
        shared_driver.quit()
    
    return results

# 测试函数
if __name__ == "__main__":
    # 测试多个订单
    order_numbers = [
        "CW20250319108248-JP",
        "CW20250327042875-JP",
    ]
    
    username = "Chessia.Xiong"
    password = "ZXCzxczxc1230"
    
    logger.info("开始批量处理 %d 个订单", len(order_numbers))
    results = get_shipping_info_batch(order_numbers, username, password)
    
    # 打印结果
    logger.info("\n处理结果:")
    for order_no, result in results.items():
        logger.info(f"订单号: {order_no}")
        logger.info(f"物流信息: {result}")
        logger.info("-" * 50)